﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AlgoritmTeorija
{
    public partial class BucketSort : Form
    {

        protected string FileName = "Data.txt";
        private BackgroundWorker _bw = new BackgroundWorker();

        public BucketSort()
        {
            InitializeComponent();
            _bw.DoWork += bw_DoWork;
        }

        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            if (rdFile.Checked)
                doBucketSort();
            else
                doBucketSortRAM();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            DisplayData(FileName);
            _bw.RunWorkerAsync();
        }

        private void btnDisplayData_Click(object sender, EventArgs e)
        {
            DisplayData(FileName);
        }

        private void btnRandom_Click(object sender, EventArgs e)
        {
            RandomDataHelper rd = new RandomDataHelper(FileName);
            rd.GenerateRandomNumbers(Convert.ToInt32(txtQuantity.Text));
            DisplayData(FileName);

        }

        private void DisplayData(string fileName)
        {
            FileHelper fh = new FileHelper(fileName, FileMode.Open);
            txtData.Text = fh.GetAllFile();
        }

        private void txtQuantity_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = !char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar);
        }


        #region BUCKET SORT

        private void doBucketSortRAM()
        {
            int[] list = null;
            string[] tempList = null;
            FileHelper fh = new FileHelper(FileName, FileMode.Open);
            tempList = fh.GetAllFile().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            txtData.Invoke((MethodInvoker)delegate { txtData.Text = fh.GetAllFile();
            });
            progressBar.Invoke((MethodInvoker) delegate{progressBar.Maximum = fh.Length;});
            TimeHelper th = new TimeHelper();

            th.StartTimer();


            if (tempList.Length == 0) 
                return;

            list = new int[tempList.Length];
            int currIndex = 0;
            foreach (string str in tempList)
            {
                list[currIndex] = Convert.ToInt32(str);
                currIndex++;
            }

            //variables to hold the min and max values of the
            //array, set them both to the first value in our array
            //so they're initialized
            int max = list[0];
            int min = list[0];

            //here we will loop through the array, starting at the first index (1)
            for (int i = 1; i < list.Length; i++)
            {
                //inside the loop we will find the max value in the array
                if (list[i] > max) max = list[i];
                //inside the loop we will find the min value in the array
                if (list[i] < min) min = list[i];
            }

            //create a bucket for holding the values in the array. Each
            //value will be stored in it's values's index
            //EXAMPLE: 15 will be at index 15 minus the min value
            List<int>[] holder = new List<int>[max - min + 1];

            //now inistialize our holder variable by creating a
            //new List<int>() for each value in our holder
            for (int i = 0; i < holder.Length; i++)
            {
                holder[i] = new List<int>();
            }

            //start moving values to our holder object
            for (int i = 0; i < list.Length; i++)
            {
                holder[list[i] - min].Add(list[i]);
            }

            //variable to hold the index of the
            //original array
            int k = 0;

            //now we move the items from pour temporary holder back to the array
            //in the new sorted order
            progressBarTotal.Invoke((MethodInvoker)delegate
            {
                progressBarTotal.Maximum = holder.Length;
            });
            for (int i = 0; i < holder.Length; i++)
            {
                if (holder[i].Count > 0)
                {
                    for (int j = 0; j < holder[i].Count; j++)
                    {
                        list[k] = holder[i][j];
                        k++;
                    }
                }
                progressBarTotal.Invoke((MethodInvoker)delegate
                {
                    progressBarTotal.Value = i;
                });
            }
            th.StopTimer();
            txtResult.Invoke((MethodInvoker)delegate
                                                {
                                                    StringBuilder builder = new StringBuilder();
                                                    Array.ForEach(list, x => builder.Append(x + "\r\n"));
                                                    txtResult.Text = builder.ToString();
                                                });
            MessageBox.Show("Veikimo laikas: " + th.GetDuration().ToString(), "Informacija", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void doBucketSort()
        {
            FileHelper fh = new FileHelper(FileName, FileMode.Open);
            fh.CopyFile(FileName);
            progressBar.Invoke((MethodInvoker)delegate
            {
                progressBar.Maximum = fh.Length;
            });
            TimeHelper th = new TimeHelper();

            th.StartTimer();


            if (fh.Length == 0)
                return;

            //variables to hold the min and max values of the
            //array, set them both to the first value in our array
            //so they're initialized
            int max = fh.ReadBinary(0);
            int min = fh.ReadBinary(0);

            //here we will loop through the array, starting at the first index (1)
            for (int i = 1; i < fh.Length; i++)
            {
                //inside the loop we will find the max value in the array
                if (fh.ReadBinary(i) > max) max = fh.ReadBinary(i);
                //inside the loop we will find the min value in the array
                if (fh.ReadBinary(i) < min) min = fh.ReadBinary(i);
            }

            //create a bucket for holding the values in the array. Each
            //value will be stored in it's values's index
            //EXAMPLE: 15 will be at index 15 minus the min value
            int holdersCount = max - min + 1;
            FileHelper[] holder = new FileHelper[holdersCount];
            //now inistialize our holder variable by creating a
            //new List<int>() for each value in our holder
            for (int i = 0; i < holdersCount; i++)
            {
                holder[i] = new FileHelper(i + ".bucket", FileMode.Create);
            }

            //start moving values to our holder object
            for (int i = 0; i < fh.Length; i++)
            {
                holder[fh.ReadBinary(i) - min].WriteBinary(fh.ReadBinary(i));
                fh.opCount++;
            }

            //variable to hold the index of the
            //original array
            int k = 0;

            //now we move the items from pour temporary holder back to the array
            //in the new sorted order
            progressBarTotal.Invoke((MethodInvoker)delegate
            {
                progressBarTotal.Maximum = holder.Length;
            });
            for (int i = 0; i < holder.Length; i++)
            {
                if (holder[i].Length > 0)
                {
                    for (int j = 0; j < holder[i].Length; j++)
                    {
                        fh.WriteBinary(k, holder[i].ReadBinary(j));
                        fh.opCount++;
                        k++;
                    }
                }
                progressBarTotal.Invoke((MethodInvoker)delegate
                {
                    progressBarTotal.Value = i;
                });
            }
            th.StopTimer();
            txtResult.Invoke((MethodInvoker)delegate
            {
                txtResult.Text = fh.GetAllFile();
            });
            MessageBox.Show("Veikimo laikas: " + th.GetDuration().ToString() + "\r\nOperacijų skaičius: " + fh.opCount + "\r\nPS. Paspaudus OK, bus ištrinti laikini .bucket failai.", "Informacija", MessageBoxButtons.OK, MessageBoxIcon.Information);
            for (int i = 0; i < holdersCount; i++)
            {
                File.Delete(i + ".bucket");
            }
        }

        #endregion

    }
}
